package com.core.servicelayer;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;


import org.hibernate.Session;
import org.hibernate.Transaction;

import com.core.hibernate.ExceptionHandler;
import com.core.hibernate.HibernateFetchRequest;
import com.core.hibernate.exceptionevent.ExceptionEvent;
import com.core.managers.SessionFactoryManager;
import com.core.protocols.IHibernateDelegate;
import com.core.protocols.IHibernateFetchRequestDelegate;
import com.core.protocols.IHibernateParentEnumeratorDelegate;
import com.core.protocols.IKVObject;
import com.core.protocols.IServiceLayerDelegate;
import com.core.utils.HQLConnection;
import com.core.utils.HibernateParameter;
import com.model.KeyValue;

public abstract class HibernateServiceLayer
        extends ServiceLayer
        implements IHibernateFetchRequestDelegate {


	private Serializable        userInfo                  = null;
	private Set <String>        expandEntities            = null;
	private Set <HQLConnection> expandEntitiesConnections = null;



	abstract public void enumerateParentObjectsWithDelegate ( IKVObject kvObject,
	                                                          IHibernateParentEnumeratorDelegate delegate );



	abstract public Class <? extends IKVObject> entityClass ();



	public Object getUserInfo () {

		return userInfo;
	}



	public Set <HQLConnection> getExpandEntitiesConnections () {

		return expandEntitiesConnections;
	}



	public void setExpandEntitiesConnections ( Set <HQLConnection> expandEntitiesConnections ) {

		this.expandEntitiesConnections = expandEntitiesConnections;
	}



	public void setUserInfo ( Serializable userInfo ) {

		this.userInfo = userInfo;
	}



	public Set <String> getExpandEntities () {

		return expandEntities;
	}



	public void setExpandEntities ( Set <String> expandEntities ) {

		this.expandEntities = expandEntities;
	}



	@Override
	public <T> void hibernateFetchResponse ( IHibernateDelegate request,
	                                         List <T> response,
	                                         Exception exception ) {

		request.setDelegate(null);

		IServiceLayerDelegate delegate = this.getLayerDelegate();
		if ( delegate == null ) {
			return;
		}

		delegate.responseResponseItemsList(response, this, exception);

	}



	@Override
	public void performRequestWithFilter ( String predicate,
	                                       Set <HibernateParameter> requestParams ) {

		// assert selectionCriteria != null;

		Class <?> entityClass = this.entityClass();
		assert (entityClass != null) : "hibernate service layer entityClass==null";

		HibernateFetchRequest request = new HibernateFetchRequest();
		request.setSelectionCriteria(this.selectionCriteria);
		request.setUserInfo(this.userInfo);
		request.setDelegate(this);
		request.setExpandEntities(this.expandEntities);
		request.setExpandEntitiesConnections(this.expandEntitiesConnections);
		request.performFetch(entityClass, predicate, requestParams);
	}



	protected static void sendObject ( HibernateServiceLayer layer,
	                                   IKVObject object,
	                                   IServiceLayerDelegate delegate,
	                                   Exception exception ) {

		if ( delegate == null ) {
			return;
		}
		List <IKVObject> list = null;
		if ( object != null ) {
			list = new ArrayList <IKVObject>();
			list.add(object);
		}
		delegate.responseResponseItemsList(list, layer, exception);

	}



	public static IKVObject createEntityWithTemplate ( IKVObject template,
	                                                   IServiceLayerDelegate delegate,
	                                                   Session session )
	        throws Exception {

		IKVObject result = HibernateFetchRequest.createEntityWithTemplate(template, session);
		HibernateServiceLayer.sendObject(null, result, delegate, null);

		return result;

	}



	public IKVObject mergeEntityByIDWithTemplate ( Integer id,
	                                               IKVObject template,
	                                               IServiceLayerDelegate delegate ) {

		IKVObject result = null;
		Exception exception = null;

		try {
			result = HibernateFetchRequest.mergeEntityByIDWithTemplate(id, template);

		} catch ( Exception e ) {
			ExceptionHandler.handleException(e, new ExceptionEvent(ExceptionEvent.MERGEOBJECT));
		} finally {
			HibernateServiceLayer.sendObject(this, result, delegate, exception);
		}

		return result;
	}



	public IKVObject objectByUNID ( Integer unid,
	                                Session externalSession,
	                                IServiceLayerDelegate delegate ) {

		IKVObject result = HibernateFetchRequest.objectByUNID(this.entityClass(), unid, externalSession);
		HibernateServiceLayer.sendObject(this, result, delegate, null);

		return result;
	}



	public void setCustomProperty ( Integer unid,
	                                KeyValue property,
	                                IServiceLayerDelegate delegate ) {

		Exception exception = null;
		IKVObject result = null;
		try {
			result = HibernateFetchRequest.setCustomPropertyValue(this.entityClass(), unid, property);

		} catch ( Exception e ) {
			exception = new Exception(e.getMessage());
		} finally {
			HibernateServiceLayer.sendObject(this, result, delegate, exception);
		}

	}



	public void deleteObject ( Integer objectId ) {

		if (objectId == null) {
			return;
		}
		
		Session session = SessionFactoryManager.sharedInstance().openSession();
		
		Transaction transaction = session.beginTransaction();
		
		try{
			IKVObject object = (IKVObject)session.get(this.entityClass(), objectId);
			if (object != null) {
//				session.flush();

	            
				session.delete(object);
//				session.flush();
				transaction.commit();
			}
		}catch(RuntimeException rt) {
			if (transaction.isActive()){
				transaction.rollback();
			}
		}finally{
			session.close();
		}
		
	}



}
